﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.DataModel;
using YArchitech.LIB;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;

namespace YArchitech.Plumbing
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class ReplaceSprinkler : IExternalCommand
	{
		public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
		{
			UIDocument activeUIDocument = commandData.Application.ActiveUIDocument;
			this.Doc = activeUIDocument.Document;
			Transaction transaction = null;
			Result result;
			try
			{
				FormReplaceSprinkler formReplaceSprinkler = new FormReplaceSprinkler(this.Doc);
				if (formReplaceSprinkler.ShowDialog() == DialogResult.Cancel)
				{
					result = Autodesk.Revit.UI.Result.Cancelled;
				}
				else
				{
					int num = 1;
					FamilySymbol familySymbol;
					if (formReplaceSprinkler.CurrentBtn == 1)
					{
						transaction = new Transaction(activeUIDocument.Document, "replace");
						transaction.Start();
						familySymbol = formReplaceSprinkler.Fsymbol;
						IEnumerable source = this.cmHelper.LayFamilyInstance(new List<XYZ>
						{
							new XYZ(1.0, 1.0, 1.0)
						}, familySymbol, this.Doc.ActiveView.GenLevel, 0, this.Doc);
						this.Doc.Regenerate();
						FamilyInstance familyInstance = (from Element ele in source
						where ele != null
						select ele as FamilyInstance).FirstOrDefault<FamilyInstance>();
						if (familyInstance != null)
						{
							Connector elementConnector = YJKRevitTools.GetElementConnector(familyInstance);
							if (elementConnector == null)
							{
								return Autodesk.Revit.UI.Result.Cancelled;
							}
							if (elementConnector.CoordinateSystem.BasisZ.IsAlmostEqualTo(new XYZ(0.0, 0.0, 1.0), 0.001))
							{
								num = 2;
							}
							else
							{
								if (!elementConnector.CoordinateSystem.BasisZ.IsAlmostEqualTo(new XYZ(0.0, 0.0, -1.0), 0.001))
								{
									YJKMessageBox.Information("选择的喷头不符合盈建科制族规范，不能进行喷头替换");
									return Autodesk.Revit.UI.Result.Cancelled;
								}
								num = 1;
							}
							this.Doc.DeleteElement(familyInstance);
						}
						transaction.Commit();
					}
					else
					{
						SprinklersParam sprinklersPara = formReplaceSprinkler.sprinklersPara;
						familySymbol = new SpaceFamilyDataReader().GetFamilySymbolById(sprinklersPara.Id, "Sprinkler", sprinklersPara.SymbolName, activeUIDocument.Document, BuiltInCategory.OST_Sprinklers);
						num = formReplaceSprinkler.familyCategory;
						if (num == 4)
						{
							num = 2;
						}
						if (num == 3)
						{
							num = 1;
						}
					}
					for (;;)
					{
						transaction = new Transaction(activeUIDocument.Document, "replace");
						transaction.Start();
						List<Element> list = activeUIDocument.Selection.PickElementsByRectangle("请框选要替换的喷头").ToList<Element>();
						while (list.Count <= 0)
						{
							list = activeUIDocument.Selection.PickElementsByRectangle("请框选要替换的喷头").ToList<Element>();
						}
						this.ReplaceSprinklers(list, num, familySymbol, transaction);
						transaction.Commit();
					}
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				this.EndTransation(transaction, false);
				result = Autodesk.Revit.UI.Result.Failed;
			}
			finally
			{
				this.EndTransation(transaction, true);
			}
			return result;
		}

		private void EndTransation(Transaction tran, bool beSure)
		{
			if (tran != null)
			{
				TransactionStatus status = tran.GetStatus();
                if (status == (TransactionStatus)1)
				{
					if (beSure)
					{
						tran.Commit();
						return;
					}
					tran.RollBack();
					return;
				}
                else if (status == (TransactionStatus)5)
				{
					tran.RollBack();
				}
			}
		}

		private void ReplaceSprinklers(List<Element> eleList, int sprinklerCategory, FamilySymbol fs, Transaction tran)
		{
			List<Element> list = (from e in eleList
			where e.Category.Name == "喷头"
			select e).ToList<Element>();
			List<Element> list2 = (from e in eleList
			where e.Category.Name == "喷头"
			select e).ToList<Element>();
			List<Element> sprinklersOneBranchOneSpringkler = this.GetSprinklersOneBranchOneSpringkler(list);
			foreach (Element item in sprinklersOneBranchOneSpringkler)
			{
				list2.Remove(item);
			}
			List<List<Element>> listFitteings = this.GetListFitteings(sprinklersOneBranchOneSpringkler, fs);
			List<List<Element>> listFitteings2 = this.GetListFitteings(list2, fs);
			if (listFitteings.Count > 0)
			{
				this.ReplaceSprinklers(listFitteings, sprinklerCategory, fs);
				tran.Commit();
				tran.Start();
			}
			if (listFitteings2.Count > 0)
			{
				this.ReplaceSprinklers(listFitteings2, sprinklerCategory, fs);
			}
		}

		private List<List<Element>> GetListFitteings(List<Element> listNew, FamilySymbol fs)
		{
			List<List<Element>> list = new List<List<Element>>();
			foreach (Element element in listNew)
			{
				FamilyInstance elem = element as FamilyInstance;
				if (!this.cmHelper.GetYJKElementConnector(elem).IsConnected)
				{
					this.ReplaceSymbol(element, fs);
				}
				else
				{
					List<Element> pipeAndFitting = this.GetPipeAndFitting(element);
					list.Add(pipeAndFitting);
				}
			}
			return list;
		}

		private List<Element> GetSprinklersOneBranchOneSpringkler(List<Element> list)
		{
			List<Element> list2 = new List<Element>();
			do
			{
				if (list.Count > 0)
				{
					list2.Add(list[0]);
					if (!this.cmHelper.GetYJKElementConnector(list[0]).IsConnected)
					{
						list.Remove(list[0]);
						continue;
					}
					List<Element> allSprinklersInOneBranch = this.GetAllSprinklersInOneBranch(list[0]);
					List<Element> list3 = new List<Element>();
					using (List<Element>.Enumerator enumerator = list.GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							Element item = enumerator.Current;
							list3.AddRange(from ele in allSprinklersInOneBranch
							where item.Id == ele.Id
							select item);
						}
					}
					if (list3.Count > 0)
					{
						foreach (Element item2 in list3)
						{
							list.Remove(item2);
						}
					}
				}
			}
			while (list.Count > 0);
			return list2;
		}

		private List<Element> GetAllSprinklersInOneBranch(Element ele)
		{
			List<Element> list = new List<Element>();
			Connector connectConnector = YJKRevitTools.GetConnectConnector(this.cmHelper.GetYJKElementConnector(ele));
			SearchBranch searchBranch = new SearchBranch(new ElementNode(connectConnector.Owner, connectConnector));
			searchBranch.DoSearch();
			ElementNode listRoot = searchBranch.GetListRoot();
			List<ElementNode> list2 = new List<ElementNode>();
			list2 = this.GetAllElemNode(listRoot, ref list2);
			list.Add(ele);
			foreach (ElementNode elementNode in list2)
			{
				if (elementNode.Element is FamilyInstance && (elementNode.Element as FamilyInstance).Category.Name == "喷头")
				{
					list.Add(elementNode.Element);
				}
			}
			return list;
		}

		private List<ElementNode> GetAllElemNode(ElementNode eNode, ref List<ElementNode> listENode)
		{
			if (eNode == null)
			{
				return listENode;
			}
			listENode.Add(eNode);
			this.GetAllElemNode(eNode.Next, ref listENode);
			if (eNode.SubElementNode != null)
			{
				foreach (ElementNode eNode2 in eNode.SubElementNode)
				{
					this.GetAllElemNode(eNode2, ref listENode);
				}
			}
			return listENode;
		}

		private void ReplaceSprinklers(List<List<Element>> listFittings, int sprinklerCategory, FamilySymbol fs)
		{
			foreach (List<Element> list in listFittings)
			{
				int sprinklerType = this.GetSprinklerType(list);
				if (sprinklerType == sprinklerCategory)
				{
					this.ReplaceSymbol(list[0], fs);
				}
				else if (sprinklerCategory != 3)
				{
					this.ReplaceOneSprinkler(list, sprinklerType, sprinklerCategory, fs);
				}
			}
		}

		private void ReplaceOneSprinkler(List<Element> eleList, int originType, int desType, FamilySymbol fs)
		{
			if (!this.IsUpDownSprinkler(eleList))
			{
				List<ElementId> list = new List<ElementId>();
				Line rotateLine = this.GetRotateLine(eleList);
				foreach (Element element in eleList)
				{
					list.Add(element.Id);
				}
				if (originType == 1)
				{
					ElementTransformUtils.RotateElements(this.Doc, list, rotateLine, Math.PI);
				}
				else
				{
					ElementTransformUtils.RotateElements(this.Doc, list, rotateLine, Math.PI);
				}
				this.Doc.Regenerate();
				this.ReplaceSymbol(eleList[0], fs);
			}
		}

		private void ReplaceSymbol(Element e, FamilySymbol fs)
		{
			FamilyInstance familyInstance = e as FamilyInstance;
			ConnectorSetIterator connectorSetIterator = familyInstance.MEPModel.ConnectorManager.Connectors.ForwardIterator();
			connectorSetIterator.Reset();
			connectorSetIterator.MoveNext();
			Connector connector = connectorSetIterator.Current as Connector;
			Connector connectConnector = YJKRevitTools.GetConnectConnector(connector);
			XYZ point = (familyInstance.Location as LocationPoint).Point;
			double radius = connector.Radius;
			List<XYZ> xyzList = new List<XYZ>
			{
				point
			};
			ElementSet elementSet = new ConnectHelper().LayFamilyInstance(xyzList, fs, this.Doc.ActiveView.GenLevel, 0, this.Doc);
			FamilyInstance familyInstance2 = null;
			foreach (object obj in elementSet)
			{
				Element element = (Element)obj;
				if (element != null)
				{
					familyInstance2 = (element as FamilyInstance);
					break;
				}
			}
			this.Doc.DeleteElement(e);
			this.Doc.Regenerate();
			Connector hyelementConnector = this.cmHelper.GetYJKElementConnector(familyInstance2);
			XYZ xyz = point.Subtract((familyInstance2.Location as LocationPoint).Point);
			ElementTransformUtils.MoveElement(this.Doc, familyInstance2.Id, xyz);
			hyelementConnector = this.cmHelper.GetYJKElementConnector(familyInstance2);
			if (connectConnector != null)
			{
				connectConnector.Radius = hyelementConnector.Radius;
				connectConnector.ConnectTo(hyelementConnector);
				new YJKRotateFamilyInstance().MoveFamilyInstance(hyelementConnector.Owner as FamilyInstance, hyelementConnector.CoordinateSystem.BasisX);
			}
			this.Doc.Regenerate();
		}

		public Line GetRotateLine(List<Element> eleList)
		{
			Element element = eleList[eleList.Count - 1];
			Element element2 = eleList[eleList.Count - 2];
			Line result;
			try
			{
				Line line = null;
				if (element is FamilyInstance)
				{
					XYZ xyz = null;
					Connector connector = null;
					ConnectorSetIterator connectorSetIterator = (element as FamilyInstance).MEPModel.ConnectorManager.Connectors.ForwardIterator();
					connectorSetIterator.Reset();
					while (connectorSetIterator.MoveNext())
					{
						object obj = connectorSetIterator.Current;
						Connector connector2 = obj as Connector;
						connector = YJKRevitTools.GetConnectConnector(connector2);
						xyz = connector2.Origin;
						if (connector.Owner.Id != element2.Id)
						{
							break;
						}
					}
					line = YJKLineEx.YJKGetBound(xyz, xyz.Add(connector.CoordinateSystem.BasisZ));
				}
				else
				{
					foreach (Connector connector3 in ((Pipe)element).GetConnectors())
					{
						if (!connector3.IsConnected)
						{
							line = YJKLineEx.YJKGetBound(connector3.Origin, connector3.Origin.Add(new XYZ(1.0, 0.0, 0.0)));
						}
					}
				}
				result = line;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				result = null;
			}
			return result;
		}

		public bool IsUpDownSprinkler(List<Element> eleList)
		{
			FamilyInstance familyInstance = eleList[eleList.Count - 1] as FamilyInstance;
			if (familyInstance == null)
			{
				return false;
			}
			ConnectorSet connectors = familyInstance.MEPModel.ConnectorManager.Connectors;
			if (connectors.Size == 4)
			{
				return true;
			}
			if (connectors.Size == 2)
			{
				return false;
			}
			List<XYZ> list = new List<XYZ>();
			ConnectorSetIterator connectorSetIterator = connectors.ForwardIterator();
			while (connectorSetIterator.MoveNext())
			{
				object obj = connectorSetIterator.Current;
				Connector connector = obj as Connector;
				list.Add(connector.Origin);
			}
			return this.IsVerticalTriangle(list);
		}

		public bool IsVerticalTriangle(List<XYZ> xyzList)
		{
			return !this.AlmostEqual(xyzList[0].Z, xyzList[1].Z, 0.0001) && !this.AlmostEqual(xyzList[2].Z, xyzList[1].Z, 0.0001) && !this.AlmostEqual(xyzList[0].Z, xyzList[2].Z, 0.0001);
		}

		public bool AlmostEqual(double a, double b, double precision)
		{
			return Math.Abs(a - b) < precision;
		}

		public List<Element> GetPipeAndFitting(Element e)
		{
			List<Element> list = new List<Element>();
			try
			{
				list.Add(e);
				ConnectorSetIterator connectorSetIterator = (e as FamilyInstance).MEPModel.ConnectorManager.Connectors.ForwardIterator();
				connectorSetIterator.Reset();
				connectorSetIterator.MoveNext();
				Connector connector = connectorSetIterator.Current as Connector;
				connector.AllRefs.ForwardIterator();
				Connector connectConnector = YJKRevitTools.GetConnectConnector(connector);
				Element element = null;
				if (connectConnector.Owner.Category.Id.IntegerValue == -2008049)
				{
					list.Add(connectConnector.Owner);
					element = connectConnector.Owner;
					connectConnector = YJKRevitTools.GetConnectConnector(element.GetFarestConnector(connectConnector.Origin));
				}
				list.Add(connectConnector.Owner);
				Pipe pipe = connectConnector.Owner as Pipe;
				if (pipe != null)
				{
					ConnectorSetIterator connectorSetIterator2 = pipe.ConnectorManager.Connectors.ForwardIterator();
					Connector connector2 = null;
					while (connectorSetIterator2.MoveNext())
					{
						object obj = connectorSetIterator2.Current;
						Connector connectConnector2 = YJKRevitTools.GetConnectConnector(obj as Connector);
						if (connectConnector2 != null && connectConnector2.Owner.Category.Id.IntegerValue == -2008049 && (element == null || element.Id != connectConnector2.Owner.Id))
						{
							connector2 = connectConnector2;
							break;
						}
					}
					if (connector2 != null)
					{
						list.Add(connector2.Owner);
						Element owner = connector2.Owner;
						foreach (Connector connector3 in this.cmHelper.GetYJKElementConnector(owner as FamilyInstance, (Autodesk.Revit.DB.Domain)3))
						{
							Connector connectConnector3 = YJKRevitTools.GetConnectConnector(connector3);
							if (!(connectConnector3.Owner.Id == pipe.Id) && connectConnector3.Owner.Category.Name == "管件")
							{
								list.Add(connectConnector3.Owner);
								break;
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
			return list;
		}

		public int GetSprinklerType(List<Element> eleList)
		{
			int result;
			try
			{
				ConnectorSetIterator connectorSetIterator = (eleList[0] as FamilyInstance).MEPModel.ConnectorManager.Connectors.ForwardIterator();
				connectorSetIterator.MoveNext();
				Connector connector = connectorSetIterator.Current as Connector;
				Connector connectConnector = YJKRevitTools.GetConnectConnector(connector);
				Pipe pipe = null;
				if (eleList[1] is Pipe)
				{
					pipe = (eleList[1] as Pipe);
				}
				else if (eleList.Count > 2)
				{
					pipe = (eleList[2] as Pipe);
				}
				if (pipe != null)
				{
					ConnectorSetIterator connectorSetIterator2 = pipe.ConnectorManager.Connectors.ForwardIterator();
					Connector connector2 = null;
					while (connectorSetIterator2.MoveNext())
					{
						object obj = connectorSetIterator2.Current;
						Connector connector3 = obj as Connector;
						connector2 = connector3;
                        if (connector3.Origin.Z != connectConnector.Origin.Z && connector3.ConnectorType != (ConnectorType)4)
						{
							break;
						}
					}
					double z = connector.Origin.Z;
					double z2 = connector2.Origin.Z;
					double num = z - z2;
					if (Math.Abs(num) < 0.0001)
					{
						return 3;
					}
					if (num < 0.0)
					{
						return 2;
					}
				}
				result = 1;
			}
			catch (Exception)
			{
				result = 2;
			}
			return result;
		}

		private ConnectHelper cmHelper = new ConnectHelper();

		private Document Doc;
	}
}
